﻿using Avalonia.Input;
using System;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Windows.Input;

namespace CalculatorApp
{
    public class MainWindowViewModel : INotifyPropertyChanged
    {
        // 私有字段，用于存储显示的文本、当前操作符、结果和其他操作状态
        private string _displayText = "0";  // 显示屏的默认值为 "0"
        private string _displaySymbol = "";  // 用于显示当前的运算符号
        private string _displayResult = "";  // 显示最终的运算结果
        private string _currentOperation;  // 当前正在进行的操作符
        private double _firstNumber;  // 存储第一个操作数
        private bool _isOperationPending;  // 标志是否有未完成的操作
        private bool _isNewEntry = true;  // 标志是否是新的输入
        private bool _isResultDisplayed = false;  // 标志是否刚刚显示了计算结果
        private string _displayAll;  // 用于显示所有操作记录

        // 实现 INotifyPropertyChanged 接口，用于通知 UI 属性的变化
        public event PropertyChangedEventHandler PropertyChanged;

        public MainWindowViewModel()
        {
            // 初始化命令，将按钮绑定到相应的命令
            AddDigitOrOperationCommand = new RelayCommand<string>(AddDigitOrOperation);  // 处理数字和操作符的输入
            ClearCommand = new RelayCommand(Clear);  // 处理清除操作
            EqualsCommand = new RelayCommand(Calculate);  // 处理等于操作
        }

        // 公有属性，用于绑定 UI
        public string DisplayAll
        {
            get => _displayAll;
            set
            {
                _displayAll = value;
                OnPropertyChanged(nameof(DisplayAll));  // 通知 UI 属性已更改
            }
        }

        public string DisplayText
        {
            get => _displayText;
            set
            {
                _displayText = value;
                OnPropertyChanged();  // 使用 CallerMemberName 自动获取属性名称
            }
        }

        public string DisplaySymbol
        {
            get => _displaySymbol;
            set
            {
                _displaySymbol = value;
                OnPropertyChanged();
            }
        }

        public string DisplayResult
        {
            get => _displayResult;
            set
            {
                _displayResult = value;
                OnPropertyChanged();
            }
        }

        // 命令用于处理各种用户操作
        public ICommand AddDigitOrOperationCommand { get; }  // 处理数字或操作符
        public ICommand ClearCommand { get; }  // 清除输入和结果
        public ICommand EqualsCommand { get; }  // 执行等于运算
        public ICommand NegateCommand { get; }  // 处理取反操作（可扩展）
        public ICommand PercentCommand { get; }  // 处理百分比操作（可扩展）

        // 根据输入值判断是数字还是操作符
        private void AddDigitOrOperation(string input)
        {
            if (IsOperation(input))
            {
                SetOperation(input);  // 如果是操作符，则调用 SetOperation
            }
            else
            {
                AddDigit(input);  // 如果是数字，则调用 AddDigit
            }
        }

        // 判断输入是否是操作符
        private bool IsOperation(string input)
        {
            return input == "+" || input == "-" || input == "*" || input == "/" || input == "=";
        }

        // 添加数字到显示屏
        private void AddDigit(string digit)
        {
            // 如果刚刚显示过结果，清空显示
            if (_isResultDisplayed)
            {
                DisplayAll = "";
                DisplayResult = "";
                _isResultDisplayed = false;
            }

            // 如果是新输入，则替换显示内容，否则追加
            if (_isNewEntry)
            {
                DisplayText = digit == "." ? "0." : digit;
                _isNewEntry = false;
                DisplayAll += digit;
            }
            else
            {
                // 避免重复输入小数点
                if (digit == "." && DisplayText.Contains("."))
                    return;

                DisplayText += digit;
                DisplayAll += digit;
            }
        }

        // 设置操作符并处理运算
        private void SetOperation(string operation)
        {
            if (!_isOperationPending)  // 如果当前没有进行中的操作
            {
                _firstNumber = double.Parse(DisplayText);  // 解析输入的第一个数字
                _currentOperation = operation;  // 保存当前操作符
                _isOperationPending = true;  // 标记操作进行中
                _isNewEntry = true;  // 准备接受新的输入

                // 显示操作符
                switch (operation)
                {
                    case "+":
                    case "-":
                    case "*":
                    case "/":
                        DisplaySymbol = operation;
                        break;
                    case "=":
                        Calculate();  // 如果操作符是 "=", 则执行计算
                        return;
                }
                DisplayAll += DisplaySymbol;
            }
            else
            {
                // 如果有进行中的操作，执行计算后再设置新的操作符
                Calculate();
                _currentOperation = operation;
            }
        }

        // 执行计算逻辑
        private void Calculate()
        {
            if (!_isOperationPending)
                return;

            double secondNumber = double.Parse(DisplayText);  // 获取输入的第二个数字
            double result = 0;

            try
            {
                // 根据操作符计算结果
                switch (_currentOperation)
                {
                    case "+":
                        result = _firstNumber + secondNumber;
                        break;
                    case "-":
                        result = _firstNumber - secondNumber;
                        break;
                    case "*":
                        result = _firstNumber * secondNumber;
                        break;
                    case "/":
                        if (secondNumber == 0)
                            throw new DivideByZeroException();
                        result = _firstNumber / secondNumber;
                        break;
                }

                // 更新显示结果
                DisplayAll += "=";
                DisplayResult = result.ToString();
                _firstNumber = result;  // 将结果作为下一次操作的第一个数字
                _isNewEntry = true;
                _isOperationPending = false;
                _isResultDisplayed = true;  // 标记刚刚显示了结果
            }
            catch (Exception)
            {
                DisplayText = "Error";  // 捕获错误，例如除零错误
                _isNewEntry = true;
                _isOperationPending = false;
                DisplaySymbol = "";
            }
        }

        // 清除输入和结果
        private void Clear()
        {
            DisplayText = "0";  // 重置显示屏
            DisplaySymbol = "";  // 清除操作符
            DisplayAll = "";  // 清空所有显示
            DisplayResult = "";  // 清空结果
            _firstNumber = 0;  // 重置第一个数字
            _currentOperation = null;  // 清除当前操作符
            _isOperationPending = false;  // 重置操作状态
            _isNewEntry = true;  // 重置为新输入状态
            _isResultDisplayed = false;  // 重置结果显示状态
        }

        // 通知属性已更改，刷新 UI
        protected void OnPropertyChanged([CallerMemberName] string name = null)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
        }
    }

    // RelayCommand 类：用于绑定命令和操作
    public class RelayCommand<T> : ICommand
    {
        private readonly Action<T> _execute;  // 执行操作的委托
        private readonly Func<T, bool> _canExecute;  // 判断操作是否可以执行的委托

        public RelayCommand(Action<T> execute, Func<T, bool> canExecute = null)
        {
            _execute = execute;
            _canExecute = canExecute;
        }

        // 判断命令是否可以执行
        public bool CanExecute(object parameter) => _canExecute == null || _canExecute((T)parameter);

        // 执行命令
        public void Execute(object parameter) => _execute((T)parameter);

        // 事件，当命令的可执行状态发生变化时触发
        public event EventHandler CanExecuteChanged
        {
            add { }
            remove { }
        }
    }

    // 不带参数的 RelayCommand 类，用于绑定简单操作
    public class RelayCommand : ICommand
    {
        private readonly Action _execute;
        private readonly Func<bool> _canExecute;

        public RelayCommand(Action execute, Func<bool> canExecute = null)
        {
            _execute = execute;
            _canExecute = canExecute;
        }

        // 判断命令是否可以执行
        public bool CanExecute(object parameter) => _canExecute == null || _canExecute();

        // 执行命令
        public void Execute(object parameter) => _execute();

        // 事件，当命令的可执行状态发生变化时触发
        public event EventHandler CanExecuteChanged
        {
            add { }
            remove { }
        }
    }
}
